package gov.pbc.nn.kjgl.maintenance.view;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Session;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.bstek.bdf2.core.business.IUser;
import com.bstek.bdf2.core.context.ContextHolder;
import com.bstek.bdf2.core.orm.hibernate.ISessionCallback;
import com.bstek.dorado.annotation.DataProvider;
import com.bstek.dorado.annotation.DataResolver;
import com.bstek.dorado.annotation.Expose;
import com.bstek.dorado.core.Configure;
import com.bstek.dorado.data.entity.EntityState;
import com.bstek.dorado.data.entity.EntityUtils;
import com.bstek.dorado.uploader.DownloadFile;
import com.bstek.dorado.uploader.UploadFile;
import com.bstek.dorado.uploader.annotation.FileProvider;
import com.bstek.dorado.uploader.annotation.FileResolver;
import com.bstek.uflo.client.service.ProcessClient;
import com.bstek.uflo.client.service.TaskClient;
import com.bstek.uflo.model.ProcessInstance;
import com.bstek.uflo.model.task.Task;
import com.bstek.uflo.service.ProcessService;

import gov.pbc.nn.core.bdf.entity.Dept;
import gov.pbc.nn.core.dao.CommonHibernateDao;
import gov.pbc.nn.core.dao.PbcnnCoreHibernateDao;
import gov.pbc.nn.core.dao.PbcnnCoreJdbcDao;
import gov.pbc.nn.core.utils.GetTableUtils;
import gov.pbc.nn.core.utils.MapUtils;
import gov.pbc.nn.kjgl.maintenance.entity.SysEvent;
import gov.pbc.nn.kjgl.maintenance.entity.SysEventProcessing;
import gov.pbc.nn.kjgl.maintenance.entity.SysMaterial;
import gov.pbc.nn.kjgl.maintenance.entity.SysProblem;
import gov.pbc.nn.kjgl.maintenance.handler.SysBusinessDeptLeaderAssignmentHandler;
import gov.pbc.nn.kjgl.maintenance.handler.SysBusinessPeopleAssignmentHandler;
import gov.pbc.nn.kjgl.maintenance.handler.SysOperationDeptLeaderAssignmentHandler;
import gov.pbc.nn.uflo.UfloUtils;
import gov.pbc.nn.uflo.entity.Opinion;

@Component
public class SysEventAuditPR {

	@Resource(name = CommonHibernateDao.BEAN_ID)
	private CommonHibernateDao hibernateDao;
	@Resource(name = PbcnnCoreHibernateDao.BEAN_ID)
	private PbcnnCoreHibernateDao coreHibernateDao;
	@Resource(name = PbcnnCoreJdbcDao.BEAN_ID)
	private PbcnnCoreJdbcDao coreJdbcDao;
	@Resource(name = ProcessClient.BEAN_ID)
	private ProcessClient pc;
	@Resource(name = ProcessService.BEAN_ID)
	private ProcessService processService;

	@Resource(name = TaskClient.BEAN_ID)
	private TaskClient tc;

	@DataProvider
	public SysEvent getEvent(String id) throws Exception {
		SysEvent event = this.hibernateDao.get(id, SysEvent.class);
		if (StringUtils.isNotEmpty(event.getSchemeId())) {
			SysMaterial material = (SysMaterial) this.hibernateDao.get(event.getSchemeId(), SysMaterial.class);
			event = EntityUtils.toEntity(event);
			// EntityUtils.setValue(event, "schemePath", material.getPath());
			EntityUtils.setValue(event, "schemeName", material.getFileName());
		}
		return event;
	}

	/**
	 * 获取事件处理人列表
	 * 
	 * @param username
	 * @return
	 */
	@DataProvider
	public List<Map<String, Object>> getUsers(String username) {
		List<Map<String, Object>> lists = null;
		if (username != null) {
			String sql = "select u.USERNAME_,u.CNAME_ from t_user u  INNER JOIN bdf2_user_dept ud on ud.USERNAME_=u.USERNAME_ INNER JOIN  t_dept d ON ud.DEPT_ID_=d.ID_  where  u.CNAME_ like concat(?,'%') or d.NAME_ like concat('%',?,'%') and ud.DEPT_ID_ like ?";
			lists = this.coreJdbcDao.getJdbcTemplate().query(sql,
					new String[] { username, username,
							((Dept) ContextHolder.getLoginUser().getDepts().get(0)).getCDept().getId() + "%" },
					new RowMapper<Map<String, Object>>() {

						@Override
						public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {
							Map<String, Object> map = new HashMap<String, Object>();
							map.put("username", rs.getString("USERNAME_"));
							map.put("cname", rs.getString("CNAME_"));
							return map;
						}

					});

		} else {
			String sql1 = "select u.USERNAME_,u.CNAME_ from t_user u  INNER JOIN bdf2_user_dept ud on ud.USERNAME_=u.USERNAME_ INNER JOIN  t_dept d ON ud.DEPT_ID_=d.ID_   and ud.DEPT_ID_ like ?";
			lists = this.coreJdbcDao.getJdbcTemplate().query(sql1,
					new Object[] { ((Dept) ContextHolder.getLoginUser().getDepts().get(0)).getCDept().getId() + "%" },
					new RowMapper<Map<String, Object>>() {

						@Override
						public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {
							Map<String, Object> map = new HashMap<String, Object>();
							map.put("username", rs.getString("USERNAME_"));
							map.put("cname", rs.getString("CNAME_"));
							return map;
						}

					});
		}
		return lists;
	}

	/**
	 * 获取系统的运维部门主管（南宁是处长，地市是科长）
	 * 
	 * @param operationDept
	 * @return
	 */
	@DataProvider
	public List<IUser> getOperationDeptLeader(String sysId) {
		SysOperationDeptLeaderAssignmentHandler handler = ContextHolder
				.getBean(SysOperationDeptLeaderAssignmentHandler.BEAN_ID);
		return handler.getOperationDeptLeader(sysId);
	}

	/**
	 * 获取系统的主管业务部门主管（南宁是处长，地市是科长）
	 * 
	 * @param operationDept
	 * @return
	 */
	@DataProvider
	public List<IUser> getBusinessDeptLeader(String sysId) {
		SysBusinessDeptLeaderAssignmentHandler handler = ContextHolder
				.getBean(SysBusinessDeptLeaderAssignmentHandler.BEAN_ID);
		return handler.getBusinessDeptLeader(sysId);
	}

	/**
	 * 业务主管部门领导审核时加载其部门内业务人员的意见（最新意见）
	 * 
	 * @return
	 */
	@DataProvider
	public List<Opinion> loadEventYwyOpinion(Map<String, Object> params) {
		long taskId = Long.parseLong(params.get("taskId").toString());
		String businessId = (String) params.get("businessId");
		Task task = this.tc.getTask(taskId);
		SysBusinessPeopleAssignmentHandler handler = ContextHolder.getBean(SysBusinessPeopleAssignmentHandler.BEAN_ID);
		List<String> users = handler.getBusinessPeople(businessId);
		List<Opinion> list = UfloUtils.getLatestOpinions(task.getProcessInstanceId(), businessId, "业务主管部门业务人员意见", null,
				users);
		return list;
	}

	/**
	 * 上传方案文件。
	 * 
	 * @param file
	 * @return
	 * @throws IOException
	 */
	@FileResolver
	@Transactional
	public Map<String, Object> uploadEventSchemeFile(UploadFile file, Map<String, Object> params) throws IOException {
		Map<String, Object> result = new HashMap<String, Object>();
		String eventId = (String) params.get("id");
		String filename = file.getFileName();
		SysMaterial material = null;
		Path path = null;
		File dest = null;
		// 将文件保存到实际目录中
		path = Paths.get(Configure.getString("SYS_YUNWEI_FILE_UPLOAD_PATH"), "事件管理");
		if (!Files.exists(path)) {
			path = Files.createDirectories(path);
		}
		path = path.resolve(UUID.randomUUID().toString());
		SysEvent event = (SysEvent) this.hibernateDao.get(eventId, SysEvent.class);
		material = new SysMaterial();
		material.setSysId(event.getSysId());
		material.setSysName(event.getSysName());
		material.setFileName(filename);
		material.setPath(path.toString());
		material.setType(0);// 文件类型：0，即事件相关
		this.hibernateDao.save(material);
		this.deleteSchemeFile(MapUtils.newHashMap(new String[] { "schemeId", "eventId" },
				new Object[] { event.getSchemeId(), eventId }));
		event.setSchemeId(material.getId());
		this.hibernateDao.update(event);

		dest = Files.createFile(path).toFile();
		file.transferTo(dest);
		result.put("schemeId", event.getSchemeId());
		result.put("schemeName", material.getFileName());
		return result;
	}

	@Expose
	@Transactional
	public void deleteSchemeFile(Map<String, Object> params) throws IOException {
		String schemeId = (String) params.get("schemeId");
		final String eventId = (String) params.get("eventId");
		if (StringUtils.isNotEmpty(schemeId)) {
			SysMaterial ma = (SysMaterial) this.hibernateDao.get(schemeId, SysMaterial.class);
			if (ma != null) {
				String path = ma.getPath();
				this.hibernateDao.delete(ma);

				final String hql = "update " + SysEvent.class.getName() + " set schemeId=null where id=:eventId";
				this.hibernateDao.doInHibernateSession(new ISessionCallback<Void>() {

					@Override
					public Void doInSession(Session session) {
						session.createQuery(hql).setString("eventId", eventId).executeUpdate();
						return null;
					}

				});
				Files.deleteIfExists(Paths.get(path));
			}
		}
	}

	/**
	 * 下载方案文件
	 * 
	 * @param eventId
	 * @return
	 * @throws FileNotFoundException
	 */
	@FileProvider
	public DownloadFile downloadEventSchemeFile(Map<String, Object> params) throws FileNotFoundException {
		String schemeId = (String) params.get("schemeId");
		SysMaterial ma = (SysMaterial) this.hibernateDao.get(schemeId, SysMaterial.class);
		String path = ma.getPath();
		File file = new File(path);
		DownloadFile df = new DownloadFile(file);
		df.setFileName(ma.getFileName());
		return df;
	}

	/**
	 * 运维人员完成任务，在该过程中操作人可能上传了方案文件.
	 * 
	 * @param event
	 *            系统事件对象，前台提交的时候需要将修改前的数据一并提交
	 * @param taskId
	 * @throws IOException
	 */
	@DataResolver
	@Transactional
	public void completeTask(SysEvent event, Map<String, Object> params) throws IOException {
		String taskId = (String) params.get("taskId");
		EntityState state = EntityUtils.getState(event);
		if (state == EntityState.MODIFIED) {
			this.hibernateDao.update(event);
		}
		Map<String, Object> variables = new HashMap<String, Object>();
		variables.put("agree", 1);

		String flowName = event.getConvertProblem() ? "to 子流程" : (event.getContinuity() ? "to 技术主管" : "to 结束");

		if (event.getConvertProblem()) {
			// 转为问题，则启动问题子流程
			SysProblem problem = new SysProblem();
			problem.setSysId(event.getSysId());
			problem.setSysName(event.getSysName());
			problem.setStartDate(event.getStartDate());
			problem.setDescription(event.getDescription());
			problem.setRemark(event.getRemark());
			problem.setFromEvent(true);
			this.hibernateDao.save(problem);
			variables.put("sysProblem", problem);
			variables.put("taskname", "【" + event.getSysName() + "】系统问题,需运维人员处理");
		} else {
			String cto = (String) params.get("cto");
			variables.put("cto", cto);
			// 运维 给 技术主管
			variables.put("taskname", "【" + event.getSysName() + "】系统事件，需技术主管审核");
		}
		this.tc.start(Long.parseLong(taskId));
		this.tc.complete(Long.parseLong(taskId), flowName, variables);
	}

	@Expose
	@Transactional
	public void completeTaskToYewu(Map<String, Object> params) {
		long taskId = Long.parseLong(params.get("taskId").toString());

		String sysName = (String) params.get("sysName");

		Map<String, Object> variables = new HashMap<String, Object>();
		// 运维 给 业务主管部门人员
		variables.put("taskname", "【" + sysName + "】系统事件，需业务主管部门人员给出意见");
		this.tc.start(taskId);
		this.tc.complete(taskId, "to 业务主管部门", variables);

	}

	/**
	 * 系统技术主管、运维部门主管审核
	 * 
	 * @param event
	 * @param taskId
	 */
	@Expose
	@Transactional
	public void completeTask(Map<String, Object> params) {
		long taskId = Long.parseLong(params.get("taskId").toString());
		String opinion = (String) params.get("opinion");
		String businessId = (String) params.get("businessId");
		String cz = (String) params.get("cz");
		int agree = Integer.parseInt(params.get("agree").toString());

		String sysName = (String) params.get("sysName");

		Task task = this.tc.getTask(taskId);
		if (StringUtils.isNotEmpty(opinion)) {
			Opinion o = new Opinion();
			o.setBusKey(businessId);
			o.setBusTable(GetTableUtils.getTablename(SysEvent.class));
			o.setOpinion(opinion);
			o.setProcessInstanceId(task.getProcessInstanceId());
			o.setProcessName(SysEventPR.PROCESS_NAME);
			o.setTaskId(taskId);
			o.setTaskName(task.getTaskName());
			o.setNodeName(task.getNodeName());
			o.setUsername(ContextHolder.getLoginUserName());
			o.setCname(ContextHolder.getLoginUser().getCname());
			o.setDeptId(ContextHolder.getLoginUser().getDepts().get(0).getId());
			o.setDeptName(ContextHolder.getLoginUser().getDepts().get(0).getName());
			this.coreHibernateDao.save(o);
		}
		Map<String, Object> variables = new HashMap<String, Object>();
		variables.put("agree", agree);
		ProcessInstance processInstance = processService.getProcessInstanceById(task.getProcessInstanceId());
		String name = processService.getProcessVariable("taskname", processInstance).toString();
		if (StringUtils.isNotBlank(cz)) {
			variables.put("operationDeptLeader", cz);
			// 系统技术主管 点击通过 给技术 运维部门主管
			variables.put("taskname", "【" + sysName + "】系统事件，技术主管审核通过,请运维部门主管审核");
		} else {
			if (1 == agree) {
				/**
				 * 点击 通过 判断 是 谁审核通过的，如果当前taskname 为“ 需业务主管部门人员给出意见”
				 * 或者“业务主管部门处长审核不通过,重新给出意见” 则是 业务主管部门人员 给出意见 时通过的。否则 是运维部门审核通过的
				 */
				if (name.equals("【" + sysName + "】系统事件，需业务主管部门人员给出意见")
						|| name.equals("【" + sysName + "】系统事件，业务主管部门处长审核不通过,重新给出意见")) {
					variables.put("taskname", "【" + sysName + "】系统事件，业务主管部门人员已给出意见,请业务主管部门处长审核");
				} else {
					// 运维部门审核 通过的 直接给 运维人员
					variables.put("taskname", "【" + sysName + "】系统事件，运维部门主管审核通过");
				}
			} else if (0 == agree) {
				if (name.equals("【" + sysName + "】系统事件，运维部门主管审核不通过，需运维人员进行修改")) {
					// 运维部门主管 审核不通过，给技术主管，技术主管在驳回给 运维人员
					variables.put("taskname", "【" + sysName + "】系统事件，运维部门主管审核不通过，需运维人员进行修改");
				} else if (name.equals("【" + sysName + "】系统事件，技术主管审核通过,请运维部门主管审核")) {
					// 运维部门主管 不通过 给 维人员进行修改，实际上是通过 技术主管 驳回给 运维人员
					variables.put("taskname", "【" + sysName + "】系统事件，运维部门主管审核不通过，需运维人员进行修改");
				} else {
					// 系统技术主管 不通过 给 申请人
					variables.put("taskname", "【" + sysName + "】系统事件，技术主管审核不通过,需运维人员进行修改");
				}
			}
			// else {
			// variables.put("taskname", "【" + sysName +
			// "】系统事件，技术主管审核不通过,需运维人员进行修改");
			// }
		}
		this.tc.start(taskId);
		this.tc.complete(taskId, variables);
	}

	/**
	 * 业务主管部门处长审核方案和部门业务员意见，完成任务
	 * 
	 * @param params
	 */
	@Expose
	@Transactional
	public void completeTaskByAuditOpinion(Map<String, Object> params) {
		long taskId = Long.parseLong(params.get("taskId").toString());
		String opinion = (String) params.get("opinion");
		String businessId = (String) params.get("businessId");
		int agree = Integer.parseInt(params.get("agree").toString());
		int backFlow = Integer.parseInt(params.get("backFlow").toString());
		Object backUsersObject = params.get("backUsers");

		String sysName = (String) params.get("sysName");

		List<String> backUsers = (List<String>) backUsersObject;
		Task task = this.tc.getTask(taskId);

		if (StringUtils.isNotEmpty(opinion)) {
			Opinion o = new Opinion();
			o.setBusKey(businessId);
			o.setBusTable(GetTableUtils.getTablename(SysEvent.class));
			o.setOpinion(opinion);
			o.setProcessInstanceId(task.getProcessInstanceId());
			o.setProcessName(SysEventPR.PROCESS_NAME);
			o.setTaskId(taskId);
			o.setTaskName(task.getTaskName());
			o.setNodeName(task.getNodeName());
			o.setUsername(ContextHolder.getLoginUserName());
			o.setCname(ContextHolder.getLoginUser().getCname());
			o.setDeptId(ContextHolder.getLoginUser().getDepts().get(0).getId());
			o.setDeptName(ContextHolder.getLoginUser().getDepts().get(0).getName());
			this.coreHibernateDao.save(o);
		}

		Map<String, Object> variables = new HashMap<String, Object>();
		variables.put("agree", agree);
		variables.put("backFlow", backFlow);
		if (agree == 1 && backFlow == -1) {// 通过，给运维人员
			variables.put("taskname", "【" + sysName + "】系统事件，业务主管部门处长审核通过");
		} else if (0 == agree && 0 == backFlow) {// 退回本部们业务员
			variables.put("taskname", "【" + sysName + "】系统事件，业务主管部门处长审核不通过,重新给出意见");
		} else if (0 == agree && 1 == backFlow) {// 退回运维
			variables.put("taskname", "【" + sysName + "】系统事件，业务主管部门处长审核不通过,需运维人员进行修改");
		}
		variables.put("backUsers", backUsers);
		this.tc.start(taskId);
		this.tc.complete(taskId, variables);

	}

	/**
	 * 运维人员记录问题处置过程，完成任务
	 * 
	 * @param event
	 * @param processingList
	 * @param taskId
	 */
	@DataResolver
	@Transactional
	public void recordEventProcessing(SysEvent event, List<SysEventProcessing> processingList, String taskId) {
		this.hibernateDao.update(event);
		for (SysEventProcessing processing : processingList) {
			this.hibernateDao.save(processing);
		}
		this.tc.start(Long.parseLong(taskId));
		this.tc.complete(Long.parseLong(taskId), "to 结束");
	}
}
